package com.hainan.bike.common.db;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collection;
import java.util.Iterator;
import javax.sql.RowSet;
import sun.jdbc.rowset.CachedRowSet;


/**
 * <p>
 * 该类提供各种数据库访问方法，既提供控制事务的数据库访问方法，也提供不控制事务的方
 * 法。开发人员可根据具体情况选用不同的方法。
 * <p>
 * @author huang
 * @version 1.0
 */
public class DbAccess 
{
   
   /**
    * ResultSet一次从数据库取的记录数
    */
   public static final int DEFAULT_FETCH_SIZE = 30;
   
   /**
    * 执行成功标志
    */
   private static int SUCCESS = 0;
   
   /**
    * RowSet结果集的最大记录数
    */
   public static final int ROWSET_MAX_ROWS = 1000;
      
   /**
    * 查询方法，返回RowSet结果集。
    * @param sql 查询语句
    * @return RowSet
    * @throws SQLException
    * @throws java.sql.SQLException
    */
   public static RowSet executeRowSetQuery(String dbID,String sql) throws SQLException 
   {
      Connection conn = DbConnectionProvider.getConnection(dbID);

      try {
         return executeRowSetQuery(conn, sql, 0);
      } finally {
         DbUtil.closeConn(conn);
      }    
   }
   
   /**
    * 查询方法，返回RowSet结果集，记录数不超过maxRows。
    * @param sql 查询语句
    * @param maxRows 返回的结果集所包含的最大行数
    * @return
    * @throws SQLException
    * @throws java.sql.SQLException
    */
   public static RowSet executeRowSetQuery(String dbID,String sql, int maxRows) throws SQLException 
   {
      Connection conn = DbConnectionProvider.getConnection(dbID);

      try {
         return executeRowSetQuery(conn, sql, maxRows);
      } finally {
         DbUtil.closeConn(conn);
      }    
   }
   
   /**
    * 查询方法，返回RowSet结果集
    * @param conn 数据库连接，调用者负责清除
    * @param sql 查询语句
    * @param maxRows 返回的结果集所包含的最大行数
    * @return
    * @throws SQLException
    * @throws java.sql.SQLException
    */
   public static RowSet executeRowSetQuery(Connection conn, String sql, int maxRows) throws SQLException 
   {
      //参数检查
      if(sql == null || sql.equals("")) {
         throw new IllegalArgumentException(
             "DbAccess.executeRowSetQuery()参数错误，sql不能为空。");
      }
      if(maxRows < 0) {
         throw new IllegalArgumentException(
             "DbAccess.executeRowSetQuery()参数错误，参数maxRows不能小于0。");
      }

      CachedRowSet crset = new CachedRowSet();
      ResultSet rs = executeResultSetQuery(conn, sql, maxRows);
      try {
         crset.populate(rs);
      } finally {
         DbUtil.closeRs(rs);
      }

      return crset;    
   }
   
   /**
    * 查询方法，返回ResultSet结果集
    * @param conn 数据库连接，调用者负责清除
    * @param sql 查询语句
    * @return
    * @throws SQLException
    * @throws java.sql.SQLException
    */
   public static ResultSet executeResultSetQuery(Connection conn, String sql) throws SQLException 
   {
      return executeResultSetQuery(conn, sql, 0);    
   }
   
   /**
    * 查询方法，返回ResultSet结果集
    * @param conn 数据库连接，调用者负责清除
    * @param sql 查询语句
    * @param maxRows 返回的结果集所包含的最大行数
    * @return
    * @throws SQLException
    * @throws java.sql.SQLException
    */
   public static ResultSet executeResultSetQuery(Connection conn, String sql, int maxRows) throws SQLException 
   {
      //
      if(sql == null || sql.equals("")) {
         throw new IllegalArgumentException(
             "DbAccess.executeResultSetQuery()参数错误，sql不能为空。");
      }
      if(maxRows < 0) {
         throw new IllegalArgumentException(
             "DbAccess.executeResultSetQuery()参数错误，参数maxRows不能小于0。");
      }

      ResultSet rs = null;
      PreparedStatement pstmt = conn.prepareStatement(sql,
          ResultSet.TYPE_SCROLL_INSENSITIVE,
          ResultSet.CONCUR_READ_ONLY);
      pstmt.setMaxRows(maxRows);

      rs = pstmt.executeQuery();
      if(maxRows == 0 || maxRows > DEFAULT_FETCH_SIZE) {
         rs.setFetchSize(DEFAULT_FETCH_SIZE);
      } else {
         rs.setFetchSize(maxRows);
      }

      return rs;    
   }
   
   /**
    * <p>
    * 单条SQL语句更新方法，包括增、删、改，
    * 方法不控制事务提交，由调用程序控制。
    * </p>
    * @param conn 数据库连接  调用者负责清除
    * @param sql
    * @return 执行状态，0表示成功，-1表示失败
    * @throws SQLException
    * @throws java.sql.SQLException
    */
   public static int executeUpdate(Connection conn, String sql) throws SQLException 
   {
      int ret = -1;

		//参数检查	
      if(sql == null || sql.equals("")) {
         throw new IllegalArgumentException("参数错误，SQL语句不能为空。");
      }

      PreparedStatement pstmt = null;
      try {
         pstmt = conn.prepareStatement(sql);
         pstmt.executeUpdate();

         ret = SUCCESS; //执行成功
      } finally {
         DbUtil.closeStmt(pstmt);
      }
      return ret;    
   }
   
   /**
    * <p>
    * 单条SQL语句更新方法，包括增、删、改，方法控制事务提交。
    * </p>
    * @param sql
    * @return 执行状态，0表示成功，-1表示失败
    * @throws SQLException
    * @throws java.sql.SQLException
    */
   public static int executeUpdate(String dbID,String sql) throws SQLException 
   {
      int ret = -1;

      if(sql == null || sql.equals("")) {
         throw new IllegalArgumentException("参数错误，SQL语句不能为空。");
      }

      PreparedStatement pstmt = null;
      Connection conn = DbConnectionProvider.getConnection(dbID);
      try {
         pstmt = conn.prepareStatement(sql);
         pstmt.executeUpdate();

         ret = SUCCESS; //执行成功
      } finally {
         DbUtil.closeStmt(pstmt);
         DbUtil.closeConn(conn);
      }
      return ret;    
   }
   
   /**
    * <p>
    * 批更新方法，执行一批SQL语句，方法不控制事务提交，由调用程序控制，
    * 适合一次执行少量的sql语句。建议不超过50条。
    * </p>
    * @param conn
    * @param sqls
    * @return int
    * @throws SQLException
    * @throws SQLException
    * @throws java.sql.SQLException
    * @roseuid 4185A0F902DE
    */
   public static int executeBatchUpdate(Connection conn, Collection sqls) throws SQLException 
   {
      return executeBatchUpdate(conn, sqls, sqls.size());    
   }
   
   /**
    * <p>
    * 批更新方法，执行一批SQL语句，方法不控制事务提交，由调用程序控制，
    * 适合提交的SQL语句有很多条的情况，避免出现内存溢出错误。
    * </p>
    * @param conn 数据库连接 调用者负责清除
    * @param sqls 要执行的一批SQL语句
    * @param sqlCount  一次执行sqls集合中多少条SQL语句
    * @return int 执行状态，0表示成功，-1表示失败
    * @throws SQLException
    * @throws java.sql.SQLException
    * @roseuid 4185A0F9033C
    */
   public static int executeBatchUpdate(Connection conn, Collection sqls, int sqlCount) throws SQLException 
   {
      int ret = -1;

      //参数检查
      if(sqls == null || sqls.isEmpty()) {
         throw new IllegalArgumentException(
             "DbAccess.executeBatchUpdate()参数错误，sqls集合不能为空。");
      }
      if(sqlCount <= 0) {
         throw new IllegalArgumentException(
             "DbAccess.executeBatchUpdate()参数错误，sqlCount必须大于0。");
      }

      Statement stmt = null;
      try {
         stmt = conn.createStatement();

         //得到要执行的SQL语句集合
         Iterator iter = sqls.iterator();

         int i = 0;
         //循环把SQL语句加入批更新中
         while(iter.hasNext()) {
            stmt.addBatch((String) iter.next());
            i++;

            if(i % sqlCount == 0) {
                //执行批更新
               stmt.executeBatch();

               //清除stmt中的sql
               stmt.clearBatch();
            }
         }

         //执行剩余的sql
         if(i % sqlCount != 0) {
            stmt.executeBatch();
         }

         ret = SUCCESS; //执行成功
      } finally {
         DbUtil.closeStmt(stmt);
      }

      return ret;    
   }
   
   /**
    * <p>
    * 批更新方法，执行一批SQL语句，方法控制事务提交，适合提交的多条SQL语句（不要超过50
    * 条）。
    * </p>
    * @param sqls 要执行的一批SQL语句
    * @return int 执行状态，0表示成功，-1表示失败
    * @throws SQLException
    * @throws java.sql.SQLException
    * @roseuid 41E4C8460157
    */
   public static int executeBatchUpdate(String dbID,Collection sqls) throws SQLException 
   {
      int ret = -1;

      //参数检查
      if(sqls == null || sqls.isEmpty()) {
         throw new IllegalArgumentException(
             "DbAccess.executeBatchUpdate()参数错误，sqls集合不能为空。");
      }

      Statement stmt = null;
      Connection conn = DbConnectionProvider.getConnection(dbID);
      try {
         stmt = conn.createStatement();

         //得到要执行的SQL语句集合
         Iterator iter = sqls.iterator();

         //循环把SQL语句加入批更新中
         while(iter.hasNext()) {
            stmt.addBatch((String) iter.next());

         }

         //执行sql
         stmt.executeBatch();

         ret = SUCCESS; //执行成功
      } finally {
         DbUtil.closeStmt(stmt);
         DbUtil.closeConn(conn);
      }

      return ret;    
   }
  

}
